#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <glib.h>
#include <string.h>
#include "ssb.h"

void iterator(gpointer key, gpointer value, gpointer user_data) {
 	printf("%s %d\n", key, *(int *)value);
}

void sort_and_print_hash(GHashTable * gb_hash){
	GHashTableIter iter;
	int size = g_hash_table_size(gb_hash);

	while(size>0){
		char * key =NULL, *min_key = NULL;
		float * value = NULL, *min_value = NULL;
		g_hash_table_iter_init(&iter,gb_hash);
		while (g_hash_table_iter_next (&iter, (gpointer)&key, (gpointer)&value)){
			if(min_key == NULL){
				min_key = key;
				min_value = value;
			}else{
				if(strcmp(min_key,key)>0){
					min_key = key;
					min_value = value;
				}
			}
		}
		printf("%s %.2f\n",min_key,*min_value);
		g_hash_table_remove(gb_hash,min_key);
		size = size -1;
	}
	return;
}

int main(int argc, char ** argv){
	int fp_date , fp_lo, fp_supplier, fp_part, fp_customer;
	struct ddate tmp_date, *p;
	struct part tmp_part, *p_part;
	struct supplier tmp_sp, * p_sp;
	struct customer tmp_customer, *p_customer;
	struct lineorder tmp_lo,*p_lo;
	GHashTable * date_hash = NULL, *part_hash = NULL,*sp_hash=NULL;
	GHashTable * gb_hash = NULL, *customer_hash = NULL;
	int date_size,lo_size,part_size,supplier_size,customer_size;
	char *mp = NULL, *mp1;

	if(argc != 6){
		printf("error: data lo part supplier customer\n");
		exit(-1);
	}

	date_hash = g_hash_table_new(NULL,NULL);
	part_hash = g_hash_table_new(NULL,NULL);
	sp_hash = g_hash_table_new(NULL,NULL);
	customer_hash = g_hash_table_new(NULL,NULL);
	gb_hash = g_hash_table_new(g_str_hash,g_str_equal);

	fp_date = open(argv[1],O_RDONLY);
	date_size = lseek(fp_date,0,SEEK_END);
	mp = mmap(0,date_size,PROT_READ,MAP_SHARED,fp_date,0);

	while(date_size>0){
		p = (struct ddate *) malloc(sizeof(struct ddate));
		memcpy(p,mp,sizeof(struct ddate));
		g_hash_table_insert(date_hash,GINT_TO_POINTER(p->datekey),p);
		date_size -= sizeof(struct ddate);
		mp += sizeof(struct ddate);
	}

	fp_supplier = open(argv[4],O_RDONLY);
	supplier_size = lseek(fp_supplier,0,SEEK_END);
	mp1 = mmap(0,supplier_size,PROT_READ,MAP_SHARED,fp_supplier,0);

	while(supplier_size>0){
		supplier_size -= sizeof(struct supplier);
		mp = mp1 + supplier_size;
		if(strncmp(((struct supplier*)mp)->region,"AMERICA",7)!=0)
			continue;
		
		p_sp = (struct supplier *) malloc(sizeof(struct supplier));
		memcpy(p_sp,mp,sizeof(struct supplier));
		g_hash_table_insert(sp_hash,GINT_TO_POINTER(p_sp->suppkey),p_sp);
	}

	fp_customer = open(argv[5],O_RDONLY);
	customer_size = lseek(fp_customer,0,SEEK_END);
	mp1 = mmap(0,customer_size,PROT_READ,MAP_SHARED,fp_customer,0);

	while(customer_size>0){
		customer_size -= sizeof(struct customer);
		mp = mp1 + customer_size;
		if(strncmp(((struct customer *)mp)->region,"AMERICA",7)!=0)
			continue;

		p_customer = (struct customer *) malloc(sizeof(struct customer));
		memcpy(p_customer,mp,sizeof(struct customer));
		g_hash_table_insert(customer_hash,GINT_TO_POINTER(p_customer->custkey),p_customer);
	}

	fp_part = open(argv[3],O_RDONLY);
	part_size = lseek(fp_part,0,SEEK_END);
	mp1 = mmap(0,part_size,PROT_READ,MAP_SHARED,fp_part,0);

	while(part_size>0){
		part_size -= sizeof(struct part);
		mp = mp1 + part_size;
		if(strncmp(((struct part*)mp)->mfgr,"MFGR#1",6)!=0 && strncmp(((struct part*)mp)->mfgr,"MFGR#2",6)!=0)
			continue;

		p_part = (struct part *)malloc(sizeof(struct part));
		memcpy(p_part,mp,sizeof(struct part));
		g_hash_table_insert(part_hash,GINT_TO_POINTER(p_part->partkey),p_part);

	}

	fp_lo = open(argv[2],O_RDONLY);
	lo_size = lseek(fp_lo,0,SEEK_END);
	mp1 = mmap(0,lo_size,PROT_READ,MAP_SHARED,fp_lo,0);

	while(lo_size>0){
		lo_size -= sizeof(struct lineorder);
		mp = mp1 + lo_size;
		p = (struct ddate *) g_hash_table_lookup(date_hash,GINT_TO_POINTER(((struct lineorder*)mp)->orderdate));
		if(p == NULL)
			continue;

		p_sp = (struct supplier*) g_hash_table_lookup(sp_hash,GINT_TO_POINTER(((struct lineorder*)mp)->suppkey));
		if (p_sp == NULL)
			continue;

		p_customer = (struct customer *) g_hash_table_lookup(customer_hash,GINT_TO_POINTER(((struct lineorder*)mp)->custkey));

		if (p_customer == NULL)
			continue;

		p_part = (struct part *) g_hash_table_lookup(part_hash,GINT_TO_POINTER(((struct lineorder*)mp)->partkey));
		if (p_part == NULL)
			continue;

		char* gb_key = NULL; 
		float * gb = NULL;
		float * sum = NULL;

		sum = (float *)malloc(sizeof(float ));
		gb_key = (char *) malloc(32*sizeof(char ));

		memset(gb_key,0,32*sizeof(char ));
		memset(sum,0,sizeof(float));

		sprintf(gb_key,"%d ",p->year);
		strncat(gb_key,p_customer->nation,15);
		gb = (float *) g_hash_table_lookup(gb_hash,gb_key);
		if (gb == NULL){
			*sum = ((struct lineorder*)mp)->revenue - ((struct lineorder*)mp)->supplycost;
			g_hash_table_insert(gb_hash,gb_key,sum);
		}else{
			*gb = *gb + ((struct lineorder*)mp)->revenue - ((struct lineorder*)mp)->supplycost;
		}
	}

	sort_and_print_hash(gb_hash);

	close(fp_date);
	close(fp_lo);
	close(fp_part);
	close(fp_supplier);
	return  0;
}
